﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using UsbLibrary;

using Microsoft.DirectX.AudioVideoPlayback;

namespace MIDIDrum
{
    public partial class NativeInput : Form
    {
        public NativeInput()
        {
            InitializeComponent();
            LoadSounds();
        }

        int parsePressed, modRemain, _lowerValues, ps3counter = 0;

        #region Handle things
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            usbGHWT360Drums.RegisterHandle(Handle);
            usbGHWTPS3Drums.RegisterHandle(Handle);
            usbRB360Drums.RegisterHandle(Handle);
            usbRBPS3Drums.RegisterHandle(Handle);
        }

        protected override void WndProc(ref Message m)
        {
            usbGHWT360Drums.ParseMessages(ref m);
            usbGHWTPS3Drums.ParseMessages(ref m);
            usbRB360Drums.ParseMessages(ref m);
            usbRBPS3Drums.ParseMessages(ref m);
            base.WndProc(ref m);	// pass message on to base form
        }
        #endregion

        #region Help icon
        private void pctInfo_MouseHover(object sender, EventArgs e)
        {
            pctInfo.BackgroundImage = MIDIDrum.Properties.Resources.information;
            while (pctInfo.Width < 32)
            {
                pctInfo.Width++;
                pctInfo.Height++;
                Application.DoEvents();
                System.Threading.Thread.Sleep(10);
            }
        }

        private void pctInfo_MouseLeave(object sender, EventArgs e)
        {
            while (pctInfo.Width > 16)
            {
                pctInfo.Width--;
                pctInfo.Height--;
                Application.DoEvents();
                System.Threading.Thread.Sleep(10);
            }
            pctInfo.BackgroundImage = MIDIDrum.Properties.Resources.information_16;
        }
        #endregion

        #region Sounds
        Audio[] audios = new Audio[128];
        private void LoadSounds()
        {
            Nini.Ini.IniDocument doc = new Nini.Ini.IniDocument("settings.ini");
            Nini.Ini.IniSection sect = doc.Sections["SOUNDS"];
            for (int i = 0; i < sect.ItemCount; i++)
            {
                Nini.Ini.IniItem item = sect.GetItem(i);
                if (!item.Name.StartsWith("#comment"))
                    audios[int.Parse(item.Name)] = new Audio("drumset/" + item.Value);
            }
        }
        #endregion

        private void TriggerNotes(Byte?[] hitVelocities)
        {
            for (int i = 0; i < 6; i++)
            {
                if (hitVelocities[i].HasValue)
                {
                    if (hitVelocities[i] > 127)
                        hitVelocities[i] = 127;
                    int number = (i == 0 ? int.Parse(txt0.Text) :
                        (i == 1 ? int.Parse(txt1.Text) :
                        (i == 2 ? int.Parse(txt2.Text) :
                        (i == 3 ? int.Parse(txt3.Text) :
                        (i == 4 ? int.Parse(txt4.Text) :
                        int.Parse(txt5.Text))))));
                    audios[number].CurrentPosition = 0;
                    audios[number].Play();
                }
            }
        }

        private void TriggerPS3Notes(Byte?[] hitVelocities)
        {
            for (int i = 0; i < 6; i++)
            {
                if (hitVelocities[i].HasValue)
                {
                    if (hitVelocities[i] > 127)
                        hitVelocities[i] = 127;
                    int number = (i == 0 ? int.Parse(txt2.Text) :
                        (i == 1 ? int.Parse(txt0.Text) :
                        (i == 2 ? int.Parse(txt1.Text) :
                        (i == 3 ? int.Parse(txt3.Text) :
                        (i == 4 ? int.Parse(txt4.Text) :
                        int.Parse(txt5.Text))))));
                    audios[number].CurrentPosition = 0;
                    audios[number].Play();
                }
            }
        }

        #region USB Events
        private void btnSettings_Click(object sender, EventArgs e)
        {
            SettingsForm form = new SettingsForm();
            form.FormClosed += delegate(object sndr, FormClosedEventArgs fcea)
            {
                LoadSounds();
            };
            form.ShowDialog();
        }

        private void usbRB360Drums_OnSpecifiedDeviceArrived(object sender, EventArgs e)
        {
            lblRB360.Text = "RockBand 360 controller is inserted";
            lblRB360.ForeColor = Color.Red;
            checkForDrums.Enabled = false;
            ps3counter = 0;
        }

        private void usbRBPS3Drums_OnSpecifiedDeviceArrived(object sender, EventArgs e)
        {
            lblRBPS3.Text = "RockBand PS3 controller is inserted";
            lblRBPS3.ForeColor = Color.Red;
            checkForDrums.Enabled = false;
            ps3counter = 0;
        }

        private void usbGHWT360Drums_OnSpecifiedDeviceArrived(object sender, EventArgs e)
        {
            lblGHWT360.Text = "GuitarHero 360 controller is inserted";
            lblGHWT360.ForeColor = Color.Red;
            checkForDrums.Enabled = false;
            ps3counter = 0;
        }

        private void usbGHWTPS3Drums_OnSpecifiedDeviceArrived(object sender, EventArgs e)
        {
            lblGHWTPS3.Text = "GuitarHero PS3 controller is inserted";
            lblGHWTPS3.ForeColor = Color.Red;
            checkForDrums.Enabled = false;
            ps3counter = 0;
        }

        private void checkForDrums_Tick(object sender, EventArgs e)
        {
            usbGHWT360Drums.CheckDevicePresent();
            usbGHWTPS3Drums.CheckDevicePresent();
            usbRBPS3Drums.CheckDevicePresent();
            usbRB360Drums.CheckDevicePresent();
        }

        private void usbRB360Drums_OnSpecifiedDeviceRemoved(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(usbRB360Drums_OnSpecifiedDeviceRemoved), new object[] { sender, e });
            }
            else
            {
                lblRB360.Text = "RockBand 360 controller is not inserted";
                lblRB360.ForeColor = Color.White;
                checkForDrums.Enabled = true;
            }
        }

        private void usbRBPS3Drums_OnSpecifiedDeviceRemoved(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(usbRBPS3Drums_OnSpecifiedDeviceRemoved), new object[] { sender, e });
            }
            else
            {
                lblRBPS3.Text = "RockBand PS3 controller is not inserted";
                lblRBPS3.ForeColor = Color.White;
                checkForDrums.Enabled = true;
            }
        }

        private void usbGHWT360Drums_OnSpecifiedDeviceRemoved(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(usbGHWT360Drums_OnSpecifiedDeviceRemoved), new object[] { sender, e });
            }
            else
            {
                lblGHWT360.Text = "GuitarHero 360 controller is not inserted";
                lblGHWT360.ForeColor = Color.White;
                checkForDrums.Enabled = true;
            }
        }

        private void usbGHWTPS3Drums_OnSpecifiedDeviceRemoved(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(usbGHWTPS3Drums_OnSpecifiedDeviceRemoved), new object[] { sender, e });
            }
            else
            {
                lblGHWTPS3.Text = "GuitarHero PS3 controller is not inserted";
                lblGHWTPS3.ForeColor = Color.White;
                checkForDrums.Enabled = true;
            }
        }

        private void usb360_DataReceived(object sender, DataRecievedEventArgs args)
        {
            if (InvokeRequired)
            {
                try
                {
                    Invoke(new DataRecievedEventHandler(usb360_DataReceived), new object[] { sender, args });
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else if (args.data.GetLength(0) == 15)
            {
                // Gets byte with the info about which buttons/pads/pedals are down
                parsePressed = args.data[11];
                if (parsePressed > 0)
                {
                    Byte?[] hitVelocites = new Byte?[6];
                    for (int i = 0; i < 6; i++)
                    {
                        // 0=Green,1=Red... (7 8 Start Back)
                        modRemain = parsePressed % 2;
                        parsePressed = parsePressed / 2;
                        if (modRemain == 1)
                        {
                            // Button is pressed, reads velocity
                            switch (i)
                            {
                                case 0: //Green;
                                    hitVelocites[i] = (byte)(260 - args.data[3]);
                                    break;
                                case 1: //Red;
                                    hitVelocites[i] = (byte)(132 - args.data[4]);
                                    break;
                                case 2: //Blue;
                                    hitVelocites[i] = (byte)(args.data[6] - 122);
                                    break;
                                case 3: //Yellow;
                                    hitVelocites[i] = (byte)(args.data[5] + 5);
                                    break;
                                case 4: //Pedal;
                                    hitVelocites[i] = (byte)(132 - args.data[8]);
                                    break;
                                case 5: //Orange;
                                    hitVelocites[i] = (byte)(260 - args.data[7]);
                                    break;
                            }
                        }
                        if (parsePressed == 0)
                            break;
                    }
                    TriggerNotes(hitVelocites);
                    hitVelocites = null;
                }
            }
        }

        private void usbPS3_DataReceived(object sender, DataRecievedEventArgs args)
        {
            if (InvokeRequired)
            {
                try
                {
                    Invoke(new DataRecievedEventHandler(usbPS3_DataReceived), new object[] { sender, args });
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else if (args.data.GetLength(0) == 28)
            {
                // Gets byte with the info about which buttons/pads/pedals are down
                parsePressed = args.data[1];
                if (parsePressed > 0)
                {
                    if (ps3counter == 0)
                    {
                        Byte?[] hitVelocites = new Byte?[6];
                        for (int i = 0; i < 6; i++)
                        {
                            // 0=Blue,1=Green...
                            modRemain = parsePressed % 2;
                            parsePressed = parsePressed / 2;
                            if (modRemain == 1)
                            {
                                switch (i)
                                {
                                    case 0: // Blue (Green 360)
                                        hitVelocites[2] = (byte)(args.data[15] + 5);
                                        break;
                                    case 1: // Green (Red 360)
                                        hitVelocites[0] = (byte)(args.data[14] + 5);
                                        break;
                                    case 2: // Red (Blue 360)
                                        hitVelocites[1] = (byte)(args.data[13] + 5);
                                        break;
                                    case 3: //Yellow;
                                        hitVelocites[i] = (byte)(args.data[12] + 5);
                                        break;
                                    case 4: //Pedal;
                                        hitVelocites[i] = (byte)(args.data[16] + 5);
                                        break;
                                    case 5: //Orange;
                                        hitVelocites[i] = (byte)(args.data[17] + 5);
                                        break;
                                }
                            }
                            if (parsePressed == 0)
                                break;
                        }
                        TriggerPS3Notes(hitVelocites);
                        hitVelocites = null;
                    }
                    ps3counter += 1;
                    if (ps3counter > 3)
                        ps3counter = 0;
                }
            }
        }
        #endregion
    }
}
